#include <curses.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
 
#define UP    0403
#define DOWN  0402
#define LEFT  0404
#define RIGHT 0405
 
#define TURN_UP    1
#define TURN_DOWN -1
#define TURN_RIGHT 2
#define TURN_LEFT -2
 
struct snake
{
 int hang;
 int lie;
 struct snake *next;
};
 
struct snake *head=NULL;
struct snake *tail=NULL;
struct snake food;
 
int key;
int turn;
int now_turn;
 
void Init_Curses()
{
 initscr();
 keypad(stdscr,1);
 noecho();
}
 
void Turn_Statu(int now_turn)
{
 if(abs(now_turn)!=abs(turn))
 turn=now_turn;
}
 
void *Snack_Direct_Control()
{
 while(1)
 {
  key=getch();
  switch(key)
  {
   case UP:
   printw("up\n");
   now_turn=TURN_UP;
   Turn_Statu(now_turn);   
   break;
   case DOWN:
   printw("down\n");
   now_turn=TURN_DOWN;
   Turn_Statu(now_turn);   
   break;
   case LEFT:
   printw("left\n");
   now_turn=TURN_LEFT;
   Turn_Statu(now_turn);   
   break;
   case RIGHT:
   printw("right\n");
   now_turn=TURN_RIGHT;
   Turn_Statu(now_turn);   
   break;
  }
 }
}
 
void Add_Snake_Node()
{
 struct snake *new=(struct snake*)malloc(sizeof(struct snake));
 switch(turn)
 {
  case TURN_UP:
  new->hang=tail->hang-1;
  new->lie=tail->lie;
  break;
  case TURN_DOWN:
  new->hang=tail->hang+1;
  new->lie=tail->lie;
  break;
  case TURN_LEFT:
  new->hang=tail->hang;
  new->lie=tail->lie-1;
  break;
  case TURN_RIGHT:
  new->hang=tail->hang;
  new->lie=tail->lie+1;
  break;
 }
 new->next=NULL;
 tail->next=new;
 tail=new;
}
 
void Init_Food()
{
 int x=rand()%19;
 int y=rand()%19;
 food.hang=x;
 food.lie=y;
 food.next=NULL;
}
 
int Deter_Food(int x,int y)
{
 if(x==food.hang&&y==food.lie)
 return 1;
 else
 return 0;
}
 
void Init_Snake_Node()
{
 Init_Food();
 turn=TURN_LEFT;
 struct snake *p;
 while(head!=NULL)
 {
  p=head;
  head=head->next;
  free(p);
 }
 head=(struct snake*)malloc(sizeof(struct snake));
 head->hang=1;
 head->lie=17;
 head->next=NULL;
 tail=head;
 Add_Snake_Node();
 Add_Snake_Node();
 Add_Snake_Node();
}
 
int Deter_Link_Node(int hang,int lie)
{
 struct snake *p=head;
 while(p!=NULL)
 {
  if(p->hang==hang&&p->lie==lie)
  return 1;
  p=p->next;
 }
return 0;
}
 
void Snack_Picture()
{
 int hang,lie;
 move(0,0);
 for(hang=0;hang<20;hang++)
 {
  if(hang==0)
  {           
   for(lie=0;lie<20;lie++)
   printw("--");
   printw("\n");
  }
  if(hang>=0&&hang<20)
  {
   for(lie=0;lie<=20;lie++)
   {
    if(lie==0||lie==20)
    printw("|");
    else if(Deter_Link_Node(hang,lie))
    printw("[]");
    else if(Deter_Food(hang,lie))
    printw("##");
    else
    printw("  ");
   }
   printw("\n");
  }
  if(hang==19)
  {
   for(lie=0;lie<20;lie++)
   printw("--");
  }
 }
 printw("\npower by Vincent-NJW\n");
}
 
void Delete_Snake_Node()
{
 struct snake *p;
 p=head;
 head=head->next;
 free(p);
}
 
int Loop_Snake()
{
 struct snake *p=head;
 while(p->next!=NULL)
 {
 
  if(tail->hang==p->hang&&tail->lie==p->lie)
  return 1;
  else
  p=p->next;
 }
}
 
void *Move_Snake()
{
 while(1)
 {	 
  Add_Snake_Node();
  if(Deter_Food(tail->hang,tail->lie))
  Init_Food();
  else
  Delete_Snake_Node();
  Snack_Picture();
  refresh();
  usleep(100000);
  if(tail->hang==-1||tail->hang==20||tail->lie==0||tail->lie==20)
  Init_Snake_Node();
  if(Loop_Snake())
  Init_Snake_Node();
 }
}
 
 
int main()
{
 Init_Curses();
 
 pthread_t t1;
 pthread_t t2;
 
 pthread_create(&t1,NULL,Snack_Direct_Control,NULL);
 
 Init_Snake_Node();
 Snack_Picture();
 
 pthread_create(&t2,NULL,Move_Snake,NULL);
 while(1);
 endwin();
 return 1;
}
 
//Vincent——NJW